package service

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"time"

	"github.com/ammyhaber/seckill/pkg/dlock"
	"github.com/ammyhaber/seckill/pkg/errcode"
	"github.com/ammyhaber/seckill/pkg/mq"
	"github.com/ammyhaber/seckill/service/order/dao"
	"github.com/ammyhaber/seckill/service/order/model"
	"github.com/go-redis/redis/v8"
)

// OrderService 订单服务
type OrderService struct {
	orderDAO         *dao.OrderDAO
	redisClient      *redis.Client
	dLock            dlock.DistributedLock
	orderMQ          *mq.RabbitMQ
	inventoryAPI     string      // 库存服务API地址
	inventoryService interface{} // 仅用于测试的内部库存服务
	httpClient       interface{} // 存储HTTP客户端实例，用于服务间通信
}

// NewOrderService 创建订单服务
func NewOrderService(orderDAO *dao.OrderDAO, redisClient *redis.Client, orderMQ *mq.RabbitMQ, inventoryAPI string) *OrderService {
	return &OrderService{
		orderDAO:     orderDAO,
		redisClient:  redisClient,
		dLock:        dlock.NewRedisLock(redisClient, "order:lock:"),
		orderMQ:      orderMQ,
		inventoryAPI: inventoryAPI,
	}
}

// SetInventoryService 设置内部库存服务（仅用于测试）
func (s *OrderService) SetInventoryService(invService interface{}) {
	s.inventoryService = invService
}

// SetHTTPClient 设置HTTP客户端
func (s *OrderService) SetHTTPClient(client interface{}) {
	// 存储HTTP客户端实例，用于服务间通信
	s.httpClient = client
}

// CreateOrder 创建订单
func (s *OrderService) CreateOrder(ctx context.Context, req *model.OrderCreateRequest) (*model.OrderInfo, error) {
	// 参数校验
	if req.UserID <= 0 || req.ProductID <= 0 || req.Quantity <= 0 {
		return nil, errors.New(errcode.GetMsg(errcode.InvalidParams))
	}

	// 获取商品信息（调用库存服务）
	productInfo, err := s.getProductInfo(ctx, req.ProductID)
	if err != nil {
		return nil, err
	}

	// 扣减库存（调用库存服务）
	success, err := s.decrInventory(ctx, req.ProductID, req.Quantity)
	if err != nil {
		return nil, err
	}
	if !success {
		return nil, errors.New(errcode.GetMsg(errcode.InventoryNotEnough))
	}

	// 生成订单ID（雪花算法或其他全局唯一ID生成方式）
	orderID := s.generateOrderID(req.UserID)

	// 计算订单过期时间（默认30分钟）
	expireTime := time.Now().Add(30 * time.Minute)

	// 创建订单
	order := &model.Order{
		ID:           orderID,
		UserID:       req.UserID,
		ProductID:    req.ProductID,
		ProductName:  productInfo.Name,
		ProductPrice: productInfo.Price,
		Quantity:     req.Quantity,
		TotalAmount:  float64(req.Quantity) * productInfo.Price,
		Status:       model.OrderStatusPending,
		ExpireTime:   &expireTime,
		CreatedAt:    time.Now(),
		UpdatedAt:    time.Now(),
	}

	// 保存订单到数据库
	err = s.orderDAO.CreateOrder(order)
	if err != nil {
		// 创建订单失败，需要回滚库存
		s.cancelInventoryDeduction(ctx, req.ProductID, req.Quantity)
		return nil, fmt.Errorf("%s: %w", errcode.GetMsg(errcode.OrderCreateFail), err)
	}

	// 发送延迟消息到RabbitMQ，用于处理超时未支付的订单
	s.sendDelayMessage(ctx, order)

	return order.ToOrderInfo(), nil
}

// PayOrder 支付订单
func (s *OrderService) PayOrder(ctx context.Context, req *model.OrderPayRequest) error {
	// 参数校验
	if req.OrderID <= 0 || req.UserID <= 0 {
		return errors.New(errcode.GetMsg(errcode.InvalidParams))
	}

	// 获取分布式锁
	lockKey := fmt.Sprintf("order:pay:%d", req.OrderID)
	lockValue, err := s.dLock.TryLock(ctx, lockKey, 10*time.Second)
	if err != nil {
		return errors.New("订单处理中，请稍后重试")
	}
	defer s.dLock.Unlock(ctx, lockKey, lockValue)

	// 查询订单
	order, err := s.orderDAO.GetOrderByID(req.OrderID, req.UserID)
	if err != nil {
		return err
	}
	if order == nil {
		return errors.New(errcode.GetMsg(errcode.OrderNotExist))
	}

	// 检查订单状态
	if order.Status != model.OrderStatusPending {
		return errors.New(errcode.GetMsg(errcode.OrderStatusInvalid))
	}

	// 检查订单是否过期
	if order.ExpireTime != nil && order.ExpireTime.Before(time.Now()) {
		return errors.New(errcode.GetMsg(errcode.OrderExpired))
	}

	// 更新订单状态为已支付
	err = s.orderDAO.PayOrder(req.OrderID, req.UserID)
	if err != nil {
		return err
	}

	// 确认库存扣减（调用库存服务）
	err = s.confirmInventoryDeduction(ctx, order.ProductID, order.Quantity)
	if err != nil {
		log.Printf("确认库存扣减失败: %v", err)
		// 这里不回滚订单状态，因为订单已支付成功
		// 可以通过定时任务或消息队列重试确认库存扣减
	}

	return nil
}

// CancelOrder 取消订单
func (s *OrderService) CancelOrder(ctx context.Context, req *model.OrderCancelRequest) error {
	// 参数校验
	if req.OrderID <= 0 || req.UserID <= 0 {
		return errors.New(errcode.GetMsg(errcode.InvalidParams))
	}

	// 获取分布式锁
	lockKey := fmt.Sprintf("order:cancel:%d", req.OrderID)
	lockValue, err := s.dLock.TryLock(ctx, lockKey, 10*time.Second)
	if err != nil {
		return errors.New("订单处理中，请稍后重试")
	}
	defer s.dLock.Unlock(ctx, lockKey, lockValue)

	// 查询订单
	order, err := s.orderDAO.GetOrderByID(req.OrderID, req.UserID)
	if err != nil {
		return err
	}
	if order == nil {
		return errors.New(errcode.GetMsg(errcode.OrderNotExist))
	}

	// 检查订单状态
	if order.Status != model.OrderStatusPending {
		return errors.New(errcode.GetMsg(errcode.OrderStatusInvalid))
	}

	// 更新订单状态为已取消
	err = s.orderDAO.CancelOrder(req.OrderID, req.UserID)
	if err != nil {
		return err
	}

	// 释放库存（调用库存服务）
	err = s.cancelInventoryDeduction(ctx, order.ProductID, order.Quantity)
	if err != nil {
		log.Printf("释放库存失败: %v", err)
		// 这里不回滚订单状态，因为订单已取消成功
		// 可以通过定时任务或消息队列重试释放库存
	}

	return nil
}

// GetOrderByID 获取订单详情
func (s *OrderService) GetOrderByID(ctx context.Context, req *model.OrderQueryRequest) (*model.OrderInfo, error) {
	// 参数校验
	if req.OrderID <= 0 || req.UserID <= 0 {
		return nil, errors.New(errcode.GetMsg(errcode.InvalidParams))
	}

	// 查询订单
	order, err := s.orderDAO.GetOrderByID(req.OrderID, req.UserID)
	if err != nil {
		return nil, err
	}
	if order == nil {
		return nil, errors.New(errcode.GetMsg(errcode.OrderNotExist))
	}

	return order.ToOrderInfo(), nil
}

// GetOrdersByUserID 获取用户订单列表
func (s *OrderService) GetOrdersByUserID(ctx context.Context, userID int64, status *model.OrderStatus) ([]*model.OrderInfo, error) {
	// 参数校验
	if userID <= 0 {
		return nil, errors.New(errcode.GetMsg(errcode.InvalidParams))
	}

	// 查询订单列表
	orders, err := s.orderDAO.GetOrdersByUserID(userID, status)
	if err != nil {
		return nil, err
	}

	// 转换为订单信息列表
	orderInfos := make([]*model.OrderInfo, 0, len(orders))
	for _, order := range orders {
		orderInfos = append(orderInfos, order.ToOrderInfo())
	}

	return orderInfos, nil
}

// HandleExpiredOrders 处理过期订单
func (s *OrderService) HandleExpiredOrders(ctx context.Context) error {
	// 获取过期未支付的订单
	expiredOrders, err := s.orderDAO.GetExpiredOrders()
	if err != nil {
		return err
	}

	// 处理每个过期订单
	for _, order := range expiredOrders {
		// 更新订单状态为已取消
		err := s.orderDAO.CancelOrder(order.ID, order.UserID)
		if err != nil {
			log.Printf("取消过期订单失败, 订单ID: %d, 错误: %v", order.ID, err)
			continue
		}

		// 释放库存
		err = s.cancelInventoryDeduction(ctx, order.ProductID, order.Quantity)
		if err != nil {
			log.Printf("释放库存失败, 订单ID: %d, 错误: %v", order.ID, err)
		}
	}

	return nil
}

// 处理延迟消息（订单超时未支付）
func (s *OrderService) HandleDelayMessage(ctx context.Context, msg []byte) error {
	// 解析消息
	var order model.Order
	if err := json.Unmarshal(msg, &order); err != nil {
		return err
	}

	// 查询订单当前状态
	currentOrder, err := s.orderDAO.GetOrderByID(order.ID, order.UserID)
	if err != nil {
		return err
	}
	if currentOrder == nil {
		return errors.New("订单不存在")
	}

	// 如果订单仍然是待支付状态，则取消订单
	if currentOrder.Status == model.OrderStatusPending {
		// 更新订单状态为已取消
		err := s.orderDAO.CancelOrder(order.ID, order.UserID)
		if err != nil {
			return err
		}

		// 释放库存
		err = s.cancelInventoryDeduction(ctx, order.ProductID, order.Quantity)
		if err != nil {
			log.Printf("释放库存失败, 订单ID: %d, 错误: %v", order.ID, err)
		}
	}

	return nil
}

// 发送延迟消息
func (s *OrderService) sendDelayMessage(ctx context.Context, order *model.Order) {
	// MQ为空时跳过（测试环境）
	if s.orderMQ == nil {
		log.Printf("RabbitMQ未配置，跳过发送延迟消息")
		return
	}

	// 序列化订单信息
	orderBytes, err := json.Marshal(order)
	if err != nil {
		log.Printf("序列化订单失败: %v", err)
		return
	}

	// 发送到延迟队列
	err = s.orderMQ.PublishMessage(ctx, orderBytes)
	if err != nil {
		log.Printf("发送延迟消息失败: %v", err)
	}
}
